#pragma once

#include <SDL/SDL.h>

typedef ::Uint32 SdlColor;

#define READ_COLOR_COMPONENT(ch, component) \
if (ch >= '0' && ch <= '9') {\
    component = (ch - '0');\
}\
else if (ch >= 'a' && ch <= 'f') {\
    component = 10 + ch - 'a';\
}\
else if (ch >= 'A' && ch <= 'F') {\
    component = 10 + ch - 'A';\
}\
else {\
    return 0;\
}

#define READ_1_COLOR_BYTE(str, result, num) {\
    char ch = *str++;\
    SdlColor component;\
    READ_COLOR_COMPONENT(ch, component);\
    result |= ((component + (component << 4)) << (num * 8));\
}

#define READ_2_COLOR_BYTES(str, result, num) {\
    char ch1 = *str++;\
    char ch2 = *str++;\
    SdlColor component1;\
    SdlColor component2;\
    READ_COLOR_COMPONENT(ch1, component1);\
    READ_COLOR_COMPONENT(ch2, component2);\
    result |= ((component1 + (component2 << 4)) << (num * 8));\
}

/**
 * Converts string given to it's SDL color counterpart.
 * #RRGGBBAA
 */
static inline SdlColor color_from_string(const char * str) {
    if (*str++ != '#') {
        // TODO: parse named color, e.g. 'blue', 'red', 'brown'...
        return 0;
    }

    SdlColor tmp;

    switch (strlen(str)) {
    case 3:
        // 3-component color notation (no alpha)
        tmp = 0xFF000000; // init default alpha value
        READ_1_COLOR_BYTE(str, tmp, 2);
        READ_1_COLOR_BYTE(str, tmp, 1);
        READ_1_COLOR_BYTE(str, tmp, 0);
        break;

    case 4:
        // 3-component color notation (with alpha)
        tmp = 0;
        READ_1_COLOR_BYTE(str, tmp, 2);
        READ_1_COLOR_BYTE(str, tmp, 1);
        READ_1_COLOR_BYTE(str, tmp, 0);
        READ_1_COLOR_BYTE(str, tmp, 3); // alpha
        break;

    case 6:
        // 6-component color notation (no alpha)
        tmp = 0xFF000000; // init default alpha value
        READ_2_COLOR_BYTES(str, tmp, 2);
        READ_2_COLOR_BYTES(str, tmp, 1);
        READ_2_COLOR_BYTES(str, tmp, 0);
        break;

    case 8:
        // 6-component color notation (with alpha)
        tmp = 0; // init default alpha value
        READ_2_COLOR_BYTES(str, tmp, 2);
        READ_2_COLOR_BYTES(str, tmp, 1);
        READ_2_COLOR_BYTES(str, tmp, 0);
        READ_2_COLOR_BYTES(str, tmp, 3);
        break;

    default:
        return 0;
    }

    return tmp;
}

/**
 * Minimum buffer length for color_to_string function.
 */
static const int color_to_string_buf_len = 10;

static const char * hex_numbers = "0123456789abcdef";


#define CONVERT_COLOR_BYTE(buf, color_byte) {\
    SdlColor tmpc = color_byte;\
    *buf++ = hex_numbers[tmpc & 0xf];\
    *buf++ = hex_numbers[tmpc >> 8];\
}

/**
 * Converts color given to the buffer.
 * \param color Color in SDL notation, e.g. ARGB
 * \param buf Buffer of AT LEAST 10 character length
 */
static inline void color_to_string(SdlColor color, char * buf) {
    *buf++ = '#';
    CONVERT_COLOR_BYTE(buf, (color >> 16) & 0xff);
    CONVERT_COLOR_BYTE(buf, (color >> 8) & 0xff);
    CONVERT_COLOR_BYTE(buf, color & 0xff);
    CONVERT_COLOR_BYTE(buf, (color >> 24) & 0xff);
    *buf++ = 0;
}
